﻿#include "common.h" // 包含预编译头文件
#include "TranscodeWindow.h"

TranscodeWindow::TranscodeWindow(QWidget *parent)
	: QMainWindow(parent)
	, window_closed(false)
	, transcoder(nullptr)
	, input_file("")
	, output_file("")
	, input_file_suffix("")
	, output_file_suffix("")
	, start_time(0)
	, input_pcm_window(nullptr)
	, output_pcm_window(nullptr)
	, inout_window_count(0)
	//, transcodeThread(nullptr)
	//, isTranscoding(false)
{
	ui.setupUi(this);

	connect(ui.pushButton_quit, SIGNAL(clicked()), this, SLOT(close()));
	connect(ui.pushButton_transcode, SIGNAL(clicked()), this, SLOT(transcodeStart()));

	connect(ui.toolButton_input, &QToolButton::clicked, this, &TranscodeWindow::openInputFile);
	connect(ui.toolButton_outpath, &QToolButton::clicked, this, &TranscodeWindow::openOutputPath);
    connect(ui.comboBox, &QComboBox::currentIndexChanged, this, &TranscodeWindow::getOutAudioSuffix);
	//startInSubThread();
}

TranscodeWindow::~TranscodeWindow()
{
	delete transcoder;
	//delete transcodeThread;
	qDebug() << "TranscodeWindow::~TranscodeWindow()";
}

bool TranscodeWindow::isClosed() const
{
	return window_closed;
}

void TranscodeWindow::closeEvent(QCloseEvent* event)
{
    emit closeSignal();
	window_closed = true;
    event->accept();  // 接受关闭请求
}

void TranscodeWindow::openInputFile()
{
	QFileDialog fileDialog(this);
	fileDialog.setFileMode(QFileDialog::ExistingFile);
	fileDialog.setNameFilter(tr("Audio files (*.mp3 *.wav *.flac *.aac *.ogg *.m4a *.pcm)"));
	if (fileDialog.exec()) {
		QStringList fileNames = fileDialog.selectedFiles();
		ui.lineEdit_input->setText(fileNames.first());

		// 获取文件后缀
		QFileInfo fileInfo(fileNames.first());

		ui.lineEdit_outpath->setText(fileInfo.absolutePath()); // 只显示路径

		ui.lineEdit_outname->setText(fileInfo.fileName().section(".", 0, -2) + "." + ui.comboBox->currentText()); // 只显示文件名
	}
	output_file_suffix = ui.comboBox->currentText().toUtf8().constData(); // 格式问题，这里使用 UTF-8 编码
}

void TranscodeWindow::openOutputPath()
{
	QFileDialog fileDialog(this);
	fileDialog.setFileMode(QFileDialog::Directory);
	if (fileDialog.exec()) {
		QStringList fileNames = fileDialog.selectedFiles();
		ui.lineEdit_outpath->setText(fileNames.first());
	}
}

void TranscodeWindow::getOutAudioSuffix(int index)
{
	QString suffix = ui.comboBox->currentText();
	if (!ui.lineEdit_input->text().isEmpty()) {
		bool have_suffix = ui.lineEdit_outname->text().contains(".");
		if (!have_suffix) {
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text() + ".");
		}
		switch (index) {
		case 0:
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".mp3");
			break;
		case 1:
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".wav");
			break;
		case 2:
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".flac");
			break;
		case 3:
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".aac");
			break;
		case 4:
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".m4a");
			break;
		case 5:
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".pcm");
			break;
		}

		/*
		if (suffix == "mp3") {
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".mp3");
		}
		else if (suffix == "wav") {
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".wav");
		}
		else if (suffix == "flac") {
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".flac");
		}
		else if (suffix == "aac") {
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".aac");
		}
		else if (suffix == "ogg") {
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".ogg");
		}
		else if (suffix == "wsaud") {
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".wsaud");
		}
		else if (suffix == "wma") {
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".wma");
		}
		else if (suffix == "rka") {
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".rka");
		}
		else if (suffix == "wve") {
			ui.lineEdit_outname->setText(ui.lineEdit_outname->text().section(".", 0, -2) + ".wve");
		}
		*/
	}
	output_file_suffix = suffix.toUtf8().constData();
}

void TranscodeWindow::finishedSlot(int64_t time_now)
{
	int time_used = time_now - start_time;

	QString seconds_time = QString::number(time_used / 1000.0, 'f', 3); // 保留三位小数

	// 使用QTime来格式化时间
    /*QTime time = QTime::fromMSecsSinceStartOfDay(start_time);
    QString formatted_time = time.toString("hh:mm:ss");*/

	ui.label_massage->setText(u8"Transcod finished! Time used: " + seconds_time + "s");
	// 设置颜色为绿色
	ui.label_massage->setStyleSheet("color: green");
}

void TranscodeWindow::inoutPcmWindowClose()
{
	if (inout_window_count > 0)
		--inout_window_count;
}

void TranscodeWindow::transcodeStart()
{
	if (transcoder && transcoder->is_transcoding.exchange(true)) {
		return;
	}

	if (transcoder) {
		delete transcoder;
	}

	if (ui.lineEdit_input->text().isEmpty() || ui.lineEdit_outpath->text().isEmpty()) {
		ui.label_massage->setText(u8"Input file or output path is empty!");
		ui.label_massage->setStyleSheet("color: red");
		return;
	}

	if (ui.lineEdit_outname->text().isEmpty()) {
		ui.label_massage->setText(u8"Output file name is empty!");
		ui.label_massage->setStyleSheet("color: red");
		return;
	}

	// 文件名验证
	// 当文件名不满足要求时（含有 / \ : * ? " < > | ）
	if (ui.lineEdit_outname->text().contains("/") ||
		ui.lineEdit_outname->text().contains("\\") ||
		ui.lineEdit_outname->text().contains(":") ||
		ui.lineEdit_outname->text().contains("*") ||
		ui.lineEdit_outname->text().contains("?") ||
		ui.lineEdit_outname->text().contains("\"") ||
		ui.lineEdit_outname->text().contains("<") ||
		ui.lineEdit_outname->text().contains(">") ||
		ui.lineEdit_outname->text().contains("|"))
	{
		ui.label_massage->setText(u8"Output file name is invalid! do not contain / \\ : * ? \" < > |");
		ui.label_massage->setStyleSheet("color: red");
		return;
	}

	input_file = ui.lineEdit_input->text().toUtf8().constData();
	qDebug() << u8"output_file_suffix: " << output_file_suffix.c_str();

	if (ui.lineEdit_outname->text().contains(".") && ui.lineEdit_outname->text().count(".") > 1) {
		// 如果找到多个 . 符号，则输出错误信息
		ui.label_massage->setText(u8"Output file name is invalid! do not contain multiple .");
		ui.label_massage->setStyleSheet("color: red");
		return;
	}

	if (ui.lineEdit_outname->text().contains(".") && ui.lineEdit_outname->text().section(".", -1, -1).toLower() == output_file_suffix) {
		// 如果文件名包含正确后缀，则直接使用
		output_file = (ui.lineEdit_outpath->text() + "/" + ui.lineEdit_outname->text()).toUtf8().constData();
	}
	else if (!ui.lineEdit_outname->text().contains(".")) {
		// 如果文件名不包含后缀，则添加后缀
		output_file = ((ui.lineEdit_outpath->text() + "/" + ui.lineEdit_outname->text()) + "." + output_file_suffix.c_str()).toUtf8().constData();
	}
	else if (ui.lineEdit_outname->text().section(".", -1, -1).toLower() != output_file_suffix) {
		// 如果文件名包含错误后缀，则输出错误信息
		ui.label_massage->setText(u8"Output file name is invalid! audio format should be mp3/wav/flac/aac/m4a/pcm.");
		ui.label_massage->setStyleSheet("color: red");
		return;
	}

	qDebug() << "input_file: " << input_file.c_str();
	qDebug() << "output_file: " << output_file.c_str();

	if (input_file == output_file) {
		ui.label_massage->setText(u8"Input file and output file are the same!");
		ui.label_massage->setStyleSheet("color: red");
		return;
	}

	// 运行 ffmpeg.exe 进行音频格式转换。这里不使用 Qt 的 QProcess 类来运行 ffmpeg.exe
	/*
	QProcess *process = new QProcess(this);
	process->start("ffmpeg.exe", QStringList() << "-i" << input_file << "-acodec" << "libmp3lame" << "-ab" << "128k" << output_file);
	connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(transcodeFinish(int, QProcess::ExitStatus)));
	*/

	// 输入文件存在验证
	QFileInfo file(ui.lineEdit_input->text());
	input_file_suffix = file.suffix().toUtf8().constData();
	if (!file.exists()) {
		ui.label_massage->setText(u8"Input file does not exist!");
		ui.label_massage->setStyleSheet("color: red");
		return;
	}
	else if (file.size() == 0) {
		ui.label_massage->setText(u8"Input file is empty!");
		ui.label_massage->setStyleSheet("color: red");
		return;
	}
	else if (!file.suffix().contains(QRegularExpression("^(mp3|aac|flac|ogg|wav|m4a|pcm)$", QRegularExpression::CaseInsensitiveOption))) {
		// 文件格式验证，如果格式不支持，则输出错误信息
		ui.label_massage->setText(u8"Input file format is not supported!");
		ui.label_massage->setStyleSheet("color: red");
		return;
	}

	if (input_file_suffix == "pcm") {
		// PCM 格式音频输入
		if (input_pcm_window) {
			delete input_pcm_window;
			input_pcm_window = nullptr;
		}

		input_pcm_window = new OpenPCMWindow(this);
		input_pcm_window->setWindowTitle(u8"PCM Input Formats");
		input_pcm_window->show();
		connect(input_pcm_window, &OpenPCMWindow::finished, this, &TranscodeWindow::inoutPcmWindowClose);
		++inout_window_count;
		this->setEnabled(false);
		input_pcm_window->setEnabled(true);

		connect(input_pcm_window, &OpenPCMWindow::finished,
			[this](bool sure, QString formatSetting) {
				qDebug() << "input setting: " << formatSetting;
				if (inout_window_count == 0 && sure)
					runTranscoder();
				else if (!sure) {
					qDebug() << "input transcode canceled!";
					ui.label_massage->setText(u8"canceled Transcode");
				}
			});
		emit showMainWindowSignal();
	}
	if (output_file_suffix == "pcm") {
		// PCM 格式音频输入
		if (output_pcm_window) {
			delete output_pcm_window;
			output_pcm_window = nullptr;
		}

		output_pcm_window = new OpenPCMWindow(this);
		output_pcm_window->setWindowTitle(u8"PCM Output Formats");
		output_pcm_window->show();
		connect(output_pcm_window, &OpenPCMWindow::finished, this, &TranscodeWindow::inoutPcmWindowClose);
		++inout_window_count;
		this->setEnabled(false);
		output_pcm_window->setEnabled(true);
		connect(output_pcm_window, &OpenPCMWindow::finished,
			[this](bool sure, QString formatSetting) {
				qDebug() << "output setting: " << formatSetting;
				if (inout_window_count == 0 && sure)
					runTranscoder();
				else if (!sure) {
					qDebug() << "output transcode canceled!";
					ui.label_massage->setText(u8"canceled Transcode");
				}
			});
		emit showMainWindowSignal();
	}
	else {
		if (inout_window_count == 0)
			runTranscoder();
	}
}

void TranscodeWindow::runTranscoder()
{
	this->setEnabled(true);
	transcoder = new AudioTranscoder(input_file, output_file);
	connect(transcoder, &AudioTranscoder::transcodeFinished, this, &TranscodeWindow::finishedSlot);

	if (input_file_suffix == "pcm") {
		// PCM 格式音频输入格式设置
		transcode_pcm.is_pcm_input = true;
		transcode_pcm.in_sample_rate = input_pcm_window->ui.comboBox_sample_rate->currentText().toInt();
		 av_channel_layout_default(
			 &transcode_pcm.in_layout,
			 input_pcm_window->ui.comboBox_channels->currentText().toInt()); // ffmpeg 7.1.1 函数
		 switch (input_pcm_window->ui.comboBox_format->currentIndex()) {
		 case 0:
			 transcode_pcm.in_sample_fmt = AV_SAMPLE_FMT_S16;
			 break;
		 case 1:
			 transcode_pcm.in_sample_fmt = AV_SAMPLE_FMT_U8;
			 break;
		 case 2:
			 transcode_pcm.in_sample_fmt = AV_SAMPLE_FMT_S32;
			 break;
		 case 3:
			 transcode_pcm.in_sample_fmt = AV_SAMPLE_FMT_FLT;
			 break;
		 default:
			 transcode_pcm.in_sample_fmt = AV_SAMPLE_FMT_S16;
			 break;
		 }
	}
	if (output_file_suffix == "pcm") {
		// PCM 格式音频输出格式设置
		transcode_pcm.out_sample_rate = output_pcm_window->ui.comboBox_sample_rate->currentText().toInt();
		 av_channel_layout_default(
			 &transcode_pcm.out_layout,
			 output_pcm_window->ui.comboBox_channels->currentText().toInt()); // ffmpeg 7.1.1 函数
		 switch (output_pcm_window->ui.comboBox_format->currentIndex()) {
		 case 0:
			 transcode_pcm.out_sample_fmt = AV_SAMPLE_FMT_S16;
			 break;
		 case 1:
			 transcode_pcm.out_sample_fmt = AV_SAMPLE_FMT_U8;
			 break;
		 case 2:
			 transcode_pcm.out_sample_fmt = AV_SAMPLE_FMT_S32;
			 break;
		 case 3:
			 transcode_pcm.out_sample_fmt = AV_SAMPLE_FMT_FLT;
			 break;
		 default:
			 transcode_pcm.out_sample_fmt = AV_SAMPLE_FMT_S16;
			 break;
		 }
	}

	ui.label_massage->setText(u8"Transcoding...");
	// 如果你需要毫秒级的时间戳
	auto now = std::chrono::high_resolution_clock::now();
	auto duration = now.time_since_epoch();
	start_time = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
	transcoder->start();
}

/*
void TranscodeWindow::startInSubThread()
{
	//transcodeThread = std::thread(&TranscodeWindow::transcodeStart, this);
	//transcodeThread.detach();
}
*/

//template<typename T>
//void TranscodeWindow::runInThread(T* obj, void(T::* func)(), void* arg)
//{
//	std::thread([&]() {
//		(obj->*func)();
//		delete obj;
//		}).detach();
//}

//template void TranscodeWindow::runInThread(TranscodeWindow* obj, void(TranscodeWindow::* func)(void), void* arg);
